#include "s21_string.h"

#include <stdlib.h>

void *s21_memchr(const void *s, int c, s21_size_t n) {
  const unsigned char *p = s;
  unsigned char uc = c;

  void *res = S21_NULL;

  for (s21_size_t i = 0; i < n; i++) {
    if (p[i] == uc) {
      res = (void *)&p[i];
      break;
    }
  }

  return res;
}

int s21_memcmp(const void *s1, const void *s2, s21_size_t n) {
  const unsigned char *c1 = s1;
  const unsigned char *c2 = s2;

  int result = 0;
  for (s21_size_t i = 0; i < n; i++) {
    if (c1[i] != c2[i]) {
      result = (c1[i] - c2[i]);
      break;
    }
  }

  return result;
}

void *s21_memcpy(void *dest, const void *src, s21_size_t n) {
  unsigned char *d = (unsigned char *)dest;
  const unsigned char *s = (const unsigned char *)src;

  for (size_t i = 0; i < n; i++) {
    d[i] = s[i];
  }

  return d;
};

void *s21_memset(void *str, int c, s21_size_t n) {
  unsigned char *p = (unsigned char *)str;

  for (s21_size_t i = 0; i < n; i++) {
    p[i] = (unsigned char)c;
  }

  return str;
}

char *s21_strncat(char *dest, const char *src, s21_size_t n) {
  char *ptr = dest;

  while (*ptr != '\0') {
    ptr++;
  }

  s21_size_t i;
  for (i = 0; i < n && src[i] != '\0'; i++) {
    ptr[i] = src[i];
  }

  ptr[i] = '\0';

  return dest;
}

char *s21_strchr(const char *str, int c) {
  char *result = S21_NULL;

  while (*str != '\0') {
    if (*str == c) {
      result = (char *)str;
      break;
    }
    str++;
  }

  if (c == '\0') {
    result = (char *)str;
  }

  return result;
}

int s21_strncmp(const char *str1, const char *str2, s21_size_t n) {
  const unsigned char *c1 = (const unsigned char *)str1;
  const unsigned char *c2 = (const unsigned char *)str2;

  int result = 0;
  for (s21_size_t i = 0; i < n; i++) {
    if (c1[i] != c2[i]) {
      result = (c1[i] - c2[i]);
      break;
    }
  }

  return result;
}

char *s21_strncpy(char *dest, const char *src, s21_size_t n) {
  char *start = dest;

  while (n > 0 && *src != '\0') {
    *dest++ = *src++;
    n--;
  }

  while (n > 0) {
    *dest++ = '\0';
    n--;
  }

  return start;
}

s21_size_t s21_strcspn(const char *str1, const char *str2) {
  s21_size_t count = 0;

  int found = 0;
  for (int i = 0; str1[i] != '\0'; i++) {
    for (int j = 0; str2[j] != '\0'; j++) {
      if (str1[i] == str2[j]) {
        found = 1;
        break;
      }
    }
    if (found) break;
    count++;
  }

  return count;
}

static char buffer[1024];

char *s21_strerror(int errnum) {
  if (errnum < NUMBER_OF_ERRORS && errnum >= 0) {
    s21_strncpy(buffer, s21_error_array[errnum], 1024);
  } else {
    s21_sprintf(buffer, "%s %d", UNKNOWN, errnum);
  }
  return buffer;
}

s21_size_t s21_strlen(const char *str) {
  s21_size_t len = 0;

  while (str[len]) {
    len++;
  }

  return len;
}

char *s21_strpbrk(const char *str1, const char *str2) {
  int i, j;
  int found = 0;
  for (i = 0; str1[i] != '\0'; i++) {
    for (j = 0; str2[j] != '\0'; j++) {
      if (str1[i] == str2[j]) {
        found = 1;
        break;
      }
    }
    if (found) break;
  }

  return found ? (char *)&str1[i] : S21_NULL;
}

char *s21_strrchr(const char *str, int c) {
  const char *found = S21_NULL;

  int i;
  for (i = 0; str[i] != '\0'; i++) {
    if (str[i] == c) {
      found = &str[i];
    }
  }

  if (c == '\0' && str[i] == '\0') {
    found = &str[i];
  }

  return (char *)found;
}

char *s21_strstr(const char *haystack, const char *needle) {
  s21_size_t needle_len = s21_strlen(needle);
  s21_size_t haystack_len = s21_strlen(haystack);

  if (needle_len > haystack_len) {
    return S21_NULL;
  }

  const char *found = S21_NULL;

  s21_size_t i, j;

  for (i = 0; i <= haystack_len - needle_len; i++) {
    for (j = 0; j < needle_len; j++) {
      if (haystack[i + j] != needle[j]) {
        break;
      }
    }
    if (j == needle_len) {
      found = &haystack[i];
      break;
    }
  }

  return (char *)found;
}

char *s21_strtok(char *dest, const char *delim) {
  static char *s21_strtok_ptr = S21_NULL;
  if (dest == S21_NULL) {
    dest = s21_strtok_ptr;
    s21_strtok_ptr = S21_NULL;
  }
  if (delim != S21_NULL && dest != S21_NULL) {
    s21_strtok_ptr = S21_NULL;
    for (s21_size_t i = 0; dest[i] && s21_strtok_ptr == S21_NULL; i++) {
      if (s21_strchr(delim, (int)dest[i])) {
        if (i == 0) {
          i--;
          dest += 1;
        } else {
          if (dest[i + 1]) s21_strtok_ptr = &dest[i + 1];
          dest[i] = '\0';
        }
      }
    }
  }
  return (*dest) ? dest : S21_NULL;
}
